﻿using System;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Collections.Specialized;
using System.Windows.Input;
using System.Windows.Media;

namespace WpfControlsTest {
    public class ProjectiveControl : Selector {

        private static ProjectiveControl selectedProjectiveControl;  

        static ProjectiveControl() {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ProjectiveControl), new FrameworkPropertyMetadata(typeof(ProjectiveControl)));

            EventManager.RegisterClassHandler(typeof(ProjectiveControl), ProjectiveControl.MouseDownEvent, new MouseButtonEventHandler(onMouseDown), true);
            EventManager.RegisterClassHandler(typeof(ProjectiveControl), UpdateProjectiveControlSelectedEvent, new RoutedEventHandler(OnUpdateProjectiveControlSelected));
            EventManager.RegisterClassHandler(typeof(ProjectiveControl), ProjectiveControl.ContextMenuOpeningEvent, new ContextMenuEventHandler(OnContextMenuOpening));
        }

        /// <summary>
        /// Is projective control focused
        /// </summary>
        private static readonly DependencyPropertyKey IsProjectiveControlSelectedKey =
            DependencyProperty.RegisterAttachedReadOnly("IsProjectiveControlSelected",
                                                typeof(bool),
                                                typeof(ProjectiveControl),
                                                new FrameworkPropertyMetadata(null, 
                                                    new CoerceValueCallback(CalculateIsProjectiveControlSelected)));

        public static readonly DependencyProperty IsProjectiveControlSelectedProperty =
            IsProjectiveControlSelectedKey.DependencyProperty;

        public static bool GetIsProjectiveControlSelected(DependencyObject obj) {
            return (bool)obj.GetValue(IsProjectiveControlSelectedProperty);
        }             

        /// <summary>
        /// Background of the control when the control is selected
        /// </summary>
        /// <param name="item"></param>
        public static readonly DependencyProperty SelectedBackgroundProperty = DependencyProperty.Register("SelectedBackground", 
            typeof(Brush), 
            typeof(ProjectiveControl), 
            new FrameworkPropertyMetadata(new SolidColorBrush(Colors.LightBlue), FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender | FrameworkPropertyMetadataOptions.AffectsRender));

        public Brush SelectedBackground {
            get {
                return (Brush)base.GetValue(SelectedBackgroundProperty);
            }
            set {
                base.SetValue(SelectedBackgroundProperty, value);
            }
        }
        
        private static object CalculateIsProjectiveControlSelected(DependencyObject item, object value) {

            ProjectiveControl control = item as ProjectiveControl;
          //  if (control.ProjectiveObject == null) return false;

            // This method is called when the IsProjectionsContainerSelected property is being calculated
            // for a Projective Control.  
            bool isSelected = (item == selectedProjectiveControl) ? true : false;
            return isSelected & (ProjectionsModeHelper.GetCurrentMode() == ProjectionsMode.Selection);
        }

        private static readonly RoutedEvent UpdateProjectiveControlSelectedEvent = EventManager.RegisterRoutedEvent(
            "UpdateProjectiveControlSelected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ProjectiveControl));


        protected override void OnSelectionChanged(SelectionChangedEventArgs e) {
            //Never gets called
            base.OnSelectionChanged(e);
        }

        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) {
            base.OnItemsChanged(e);
            if ((e.Action == NotifyCollectionChangedAction.Remove) && (base.SelectedIndex == -1)) {
                int startIndex = e.OldStartingIndex + 1;
                if (startIndex > base.Items.Count) {
                    startIndex = 0;
                }

                //DslProjectionContainer item = this.FindNextDslProjectionContainer(startIndex, -1);
                //if (item != null) {
                //    item.SetCurrentValueInternal(DslProjectionContainer.IsSelectedProperty, BooleanBoxes.TrueBox);
                //}
            }
        }

        protected override void OnInitialized(EventArgs e) {
            base.OnInitialized(e);

            if (base.HasItems)
            {
                base.SetCurrentValue(Selector.SelectedIndexProperty, 0);
            }
        }

        protected override DependencyObject GetContainerForItemOverride() {
            return new ProjectionContainer();
        }

        protected override bool IsItemItsOwnContainerOverride(object item) {
            return (item is ProjectionContainer);
        }

        public override void OnApplyTemplate() {
            base.OnApplyTemplate();
        }

        static void OnUpdateProjectiveControlSelected(object sender, RoutedEventArgs args) {
            // Mark this object as the tree view item over which the mouse
            // is currently positioned.
            selectedProjectiveControl = sender as ProjectiveControl;

            // Tell that item to re-calculate the IsMouseDirectlyOverItem property
            selectedProjectiveControl.InvalidateProperty(IsProjectiveControlSelectedProperty);

            // Prevent this event from notifying other tree view items higher in the tree.
            args.Handled = true;
        }

        static void OnContextMenuOpening(object sender, ContextMenuEventArgs args)
        {
            var projectiveControl = sender as ProjectiveControl;

            // If the projectiveControl that handles this event is not the same like the one which is selected, just
            // pass the Event to be handled somewhere else
            if (selectedProjectiveControl != null && selectedProjectiveControl != projectiveControl)
            {
                args.Handled = false;
                return;
            }

            // If the projectiveControl is selected enable the context menu opening
            var isSelected = (bool)projectiveControl.GetValue(IsProjectiveControlSelectedProperty);
            args.Handled = !isSelected;  
        }

        /// <summary>
        /// MouseDown event occured on some sub-element
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        static void onMouseDown(object sender, MouseButtonEventArgs args) {
            if (ProjectionsModeHelper.GetCurrentMode() != ProjectionsMode.Selection) {
                if (selectedProjectiveControl != null) {
                    DependencyObject obj = selectedProjectiveControl;
                    obj.InvalidateProperty(IsProjectiveControlSelectedProperty);

                    selectedProjectiveControl = null;
                }

                return;
            }

            lock (IsProjectiveControlSelectedProperty) {
                // Get the element that is currently under the mouse.
                IInputElement currentProjectiveControl = Mouse.DirectlyOver;

                if (selectedProjectiveControl != null) {
                    // Tell the item that previously had the mouse that it no longer does.
                    DependencyObject oldItem = selectedProjectiveControl;
                    selectedProjectiveControl = null;
                    oldItem.InvalidateProperty(IsProjectiveControlSelectedProperty);
                }

                // See if the mouse is still over something (any element, not just a tree view item).
                if (currentProjectiveControl != null) {
                    currentProjectiveControl.RaiseEvent(new RoutedEventArgs(UpdateProjectiveControlSelectedEvent));
                }
            }
        }
    }
}
